﻿using Micro.Extensions.Utilities;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Threading;
using System.Threading.Tasks;

namespace Micro.Extensions.Log
{
    public class FileDiskWriter :IFileDiskWriter
    {
        private readonly string _appLogFolder;
        private readonly CancellationTokenSource _cancellationToken;
        private readonly BlockingCollection<HardDiskInfo> _logQueue;
        public FileDiskWriter(IOptionsMonitor<MicroLoggerOptions> options, IConfiguration configuration)
        {
            _cancellationToken = new CancellationTokenSource();
            _logQueue = new BlockingCollection<HardDiskInfo>(10240);
            var appId = configuration["Apollo:AppId"];
            if (string.IsNullOrEmpty(appId))
                appId = options.CurrentValue.ApplicationId;

            _appLogFolder = Path.Combine(options.CurrentValue.LocalPath, appId);
            if (!Directory.Exists(_appLogFolder))
                Directory.CreateDirectory(_appLogFolder);

            WriteToHardDisk();

            //初始化写一个信息
            _logQueue.Add(new HardDiskInfo
            {
                FileName = LogConst.InfoLog,
                Message = new BaseMessage
                {
                    Message = "初始化 FileDiskWriter 成功",
                    LogTime = DateTime.Now,
                    LogName = nameof(FileDiskWriter),
                    HostIPAddress = NetWorkUtil.GetIpAddress()
                }
            });
        }
        public void  Write(HardDiskInfo hardDiskInfo)
        {
            _logQueue.TryAdd(hardDiskInfo);
        }

        /// <summary>
        /// 写入磁盘
        /// </summary>
        private void WriteToHardDisk()
        {
            Task.Factory.StartNew(() =>
            {
                while (!_cancellationToken.IsCancellationRequested)
                {
                    if (_logQueue.Count > 0)
                    {
                        try
                        {
                            StreamWriter writer = null;
                            var fileName = string.Empty;
                            var count = 0;
                            while (_logQueue.TryTake(out var hdInfo, 10) && !_cancellationToken.IsCancellationRequested)
                            {
                                if (writer == null)
                                {
                                    writer = new StreamWriter(Path.Combine(_appLogFolder, hdInfo.FileName), true);
                                    fileName = hdInfo.FileName;
                                }
                                else
                                {
                                    if (fileName != hdInfo.FileName)
                                    {
                                        writer.Close();
                                        writer = new StreamWriter(Path.Combine(_appLogFolder, hdInfo.FileName), true);
                                        fileName = hdInfo.FileName;
                                    }
                                }

                                writer.WriteLine(hdInfo.Message.ToJson());
                                if (count++ > 100) //一次连续最大写入100条
                                    break;
                            }

                            writer?.Close();
                        }
                        catch (Exception e)
                        {
                            Console.WriteLine(e);//ignore
                        }
                    }

                    Thread.Sleep(1000);
                }
            }, _cancellationToken.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
        }

        public void Dispose()
        {
            _cancellationToken?.Cancel();
            _logQueue.Dispose();
        }

    }

    /// <summary>
    /// 刷入磁盘信息
    /// </summary>
    public class HardDiskInfo
    {
        public HardDiskInfo(BaseMessage message)
        {
            Message = message;
            FileName = DateTime.Now.ToString("yyyy-MM-dd#HHmm") + ".log";
        }

        public HardDiskInfo() { }

        public string FileName { get; set; }

        public BaseMessage Message { get; set; }
    }
}
